package com.gt.web.srv.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.dfa.StopChar;
import com.gt.web.api.common.R;
import com.gt.web.api.exception.BusinessException;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 工具类
 *
 * @author Yu Chaohua
 * @date 2024/3/21 10:20
 */
public class OptUtil {

    private static final int OR_STREAM_THRESHOLD = 2;
    private static final int STREAM_MAP_THRESHOLD = 13;

    /**
     * 字符串常量：{@code "false"} <br>
     */
    private static final String FALSE = "false";


    private OptUtil() {
    }

    /**
     * 寻找到第一个不为空的集合
     *
     * @param elements 集合...
     * @return 集合
     */
    @SafeVarargs
    public static <T> List<T> or(List<T>... elements) {
        if (ObjectUtil.isNull(elements)) {
            return ListUtil.empty();
        }
        return Arrays.stream(elements).filter(ObjectUtil::isNotNull).findFirst().orElse(ListUtil.empty());
    }

    /**
     * 寻找到第一个不为空的对象
     *
     * @param elements 对象...
     * @return 对象
     */
    @SafeVarargs
    public static <T> T or(T... elements) {
        if (ObjectUtil.isNull(elements)) {
            return null;
        }
        if (elements.length == OR_STREAM_THRESHOLD) {
            if (has(elements[0])) {
                return elements[0];
            }
            return elements[1];
        }
        return Arrays.stream(elements).filter(OptUtil::has).findFirst().orElse(null);
    }

    /**
     * 判断是否为空或者空集合
     *
     * @param val 待检查对象
     * @return 检查结果
     */
    public static boolean has(Object val) {
        if (val instanceof Number) {
            return NumberUtil.isValidNumber((Number) val) && NumberUtil.toBigDecimal((Number) val).compareTo(BigDecimal.ZERO) != 0;
        }
        if (val instanceof String) {
            return !CharSequenceUtil.isBlankOrUndefined(val.toString()) && !CharSequenceUtil.equalsIgnoreCase(FALSE, val.toString());
        }
        if (val instanceof Collection) {
            return CollUtil.isNotEmpty((Collection) val);
        }
        if (val instanceof Boolean) {
            return BooleanUtil.isTrue((Boolean) val);
        }
        return ObjectUtil.isNotNull(val);
    }

    /**
     * 校验集合中是否存在 code
     *
     * @param elements 待检查的集合
     * @param code     待找到的值
     * @return 是否存在
     */
    public static <T> boolean contains(List<T> elements, T code) {
        if (elements.size() < STREAM_MAP_THRESHOLD) {
            return elements.stream().anyMatch(a -> Objects.equals(a, code));
        }
        return elements.stream().collect(Collectors.toMap(a -> a, a -> true)).containsKey(code);
    }

    @SafeVarargs
    public static <T> boolean containAny(List<T> elements, T... codes) {
        if (ObjectUtil.hasEmpty(elements, codes)) {
            return false;
        }
        for (T code : codes) {
            if (elements.contains(code)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 数组去重
     *
     * @param collection 待处理的集合
     * @return 处理后的集合
     */
    public static <T> List<T> distinct(Collection<T> collection) {
        if (collection == null) {
            return Collections.emptyList();
        }
        return collection.stream().distinct().collect(Collectors.toList());
    }

    public static String join(CharSequence conjunction, String... objs) {
        return ArrayUtil.join(objs, conjunction, s -> has(s) ? s : CharSequenceUtil.EMPTY);
    }

    /**
     * 字符串过滤
     *
     * @param text            待过滤文本
     * @param filterWord      过滤词汇
     * @param isDefaultFilter 是否使用默认过滤器
     * @return
     */
    public static String strFilter(String text, List<String> filterWord, boolean isDefaultFilter) {
        if (CollUtil.isEmpty(filterWord)) {
            filterWord = new ArrayList<>();
        }
        if (isDefaultFilter) {
            filterWord.addAll(StopChar.STOP_WORD.stream().map(String::valueOf).collect(Collectors.toList()));
        }
        Set<String> finalSplitWord = new HashSet<>(filterWord);
        return or(CharSequenceUtil.filter(text, ch -> !finalSplitWord.contains(String.valueOf(ch))), CharSequenceUtil.EMPTY);
    }

    /**
     * 构建成功结果
     *
     * @param data
     * @return
     */
    public static <T> R<T> successResponse(T data) {
        return R.ok(data);
    }

    /**
     * 构建成功结果
     *
     * @param data
     * @return
     */
    public static <T> R<T> successResponse(T data, String msg) {
        R<T> restResultResponse = successResponse(data);
        restResultResponse.setMsg(msg);
        return restResultResponse;
    }

    /**
     * 构建失败结果
     *
     * @param message 错误描述
     * @return
     */
    public static <T> R<T> failResponse(String message) {
        return failResponse(500, message);
    }

    /**
     * 构建失败结果
     *
     * @param resultCode 错误码
     * @param message    错误描述
     * @return
     */
    public static <T> R<T> failResponse(Integer resultCode, String message) {
        return failResponse(resultCode, message, null);
    }


    /**
     * 构建失败结果
     *
     * @param resultCode 错误码
     * @param message    错误描述
     * @return
     */
    public static <T> R<T> failResponse(Integer resultCode, String message, T data) {
        R<T> restResultResponse = R.fail(resultCode, message);
        restResultResponse.setData(data);
        return restResultResponse;
    }

    /**
     * 是否抛出运行时异常
     *
     * @param flag
     * @param msg
     */
    public static void ifThrow(boolean flag, String msg) {
        if (BooleanUtil.isTrue(flag)) {
            ifThrow(flag, 500, msg);
        }
    }

    /**
     * 是否抛出运行时异常
     *
     * @param flag
     * @param msg
     */
    public static void ifThrow(boolean flag, Integer code, String msg) {
        if (BooleanUtil.isTrue(flag)) {
            throw new BusinessException(code, msg);
        }
    }
}
